package raft

import (
	"time"
)

// main function:maintain leader state, a special appendentries rpc, contain
// no log, to tell follower "leader is active"
//
//	1.if follower recieve heartbeat , it will restart election timer
//	2.if follower didnt recieve heartbeat for a while ,start election
//
// leader circlelife:
//
//	initialhartbeat -> heartbeat period + log replication + recieve client request
//	become follower(recieve higher term or lose most relation)
func (rf *Raft) HeartBeat() {
	wakepool_chan := make([]chan struct{}, len(rf.peers))
	donepool_chan := make([]chan struct{}, len(rf.peers))

	//allocate a go routine for each peer to send appendentries PRCs
	//method:use channel, if wake pool has mess send appendentriesargs
	for i := range rf.peers {
		if i == rf.me {
			continue
		}
		wakepool_chan[i] = make(chan struct{}) //empty sturct is 0 bit
		donepool_chan[i] = make(chan struct{})
		go func(i int) {
			for {
				select {

				case <-wakepool_chan[i]:
					args := AppendEntriesArgs{LeaderId: rf.me}
					reply := AppendEntriesReply{}
					rf.mu.Lock()
					args.Term = rf.currentTerm
					rf.mu.Unlock()

					go func() {
						if ok := rf.sendAppendEntries(i, &args, &reply); !ok {
							return
						}
						rf.mu.Lock()
						if reply.Term > rf.currentTerm {
							rf.currentTerm = reply.Term
							rf.voteFor = -1
							rf.state = FOLLOWER
							rf.mu.Unlock()
							return

						}
						rf.mu.Unlock()
					}()
				case <-donepool_chan[i]:
					return

				}
			}
		}(i)
	}

	broadcast := func() {
		for i := range rf.peers {
			if i == rf.me {
				continue
			}
			go func(i int) {
				wakepool_chan[i] <- struct{}{}
			}(i)
		}

	}

	broadcast()

	rf.HeartBeatTimer = time.NewTimer(HeartBeatTimeout)
	for {
		<-rf.HeartBeatTimer.C
		if rf.killed() || rf.state != LEADER {
			break
		}
		rf.HeartBeatTimer.Reset(HeartBeatTimeout)
		broadcast()
	}

	for i := range rf.peers {
		if i == rf.me {
			continue
		}
		go func(i int) {
			donepool_chan[i] <- struct{}{}
		}(i)
	}
}
